import Foundation
import CommonCrypto

class OSSUploadService {
    static let shared = OSSUploadService()
    
    private init() {}
    
    /// 上传文件到阿里云 OSS
    /// - Parameters:
    ///   - fileURL: 本地文件路径
    ///   - objectKey: OSS 中的对象键（文件路径）
    /// - Returns: 上传成功后的文件 URL
    func uploadFile(fileURL: URL, objectKey: String) async throws -> String {
        let config = AppConfig.OSS.self
        
        // 读取文件数据
        let fileData = try Data(contentsOf: fileURL)
        
        // 构建 OSS URL - 确保 objectKey 已经过 URL 编码
        let ossURL = "https://\(config.bucketName).\(config.endpoint)/\(objectKey)"
        guard let url = URL(string: ossURL) else {
            print("❌ [OSS] 无效的 URL: \(ossURL)")
            throw OSSError.invalidURL
        }
        
        print("🔑 [OSS] 准备上传到: \(ossURL)")
        print("🔑 [OSS] ObjectKey: \(objectKey)")
        print("🔑 [OSS] 文件大小: \(fileData.count) bytes")
        
        // 创建请求 - 需要签名认证
        var request = URLRequest(url: url)
        request.httpMethod = "PUT"
        request.httpBody = fileData
        request.setValue("text/csv", forHTTPHeaderField: "Content-Type")
        request.setValue(String(fileData.count), forHTTPHeaderField: "Content-Length")
        
        // 生成签名
        let date = RFC1123DateFormatter.string(from: Date())
        request.setValue(date, forHTTPHeaderField: "Date")
        
        print("🔑 [OSS] Date: \(date)")
        
        // 注意：签名时 resource 需要使用原始路径（不编码），但 URL 中需要编码
        // 从 objectKey 中提取原始路径（将 %20 还原为空格）
        let decodedObjectKey = objectKey.removingPercentEncoding ?? objectKey
        
        let signature = generateSignature(
            method: "PUT",
            contentType: "text/csv",
            date: date,
            ossHeaders: [:],
            resource: "/\(config.bucketName)/\(decodedObjectKey)"
        )
        
        print("🔑 [OSS] Signature: \(signature)")
        
        let authorization = "OSS \(config.accessKeyId):\(signature)"
        request.setValue(authorization, forHTTPHeaderField: "Authorization")
        
        print("🔑 [OSS] Authorization: \(authorization)")
        
        // 发送请求
        let (data, response) = try await URLSession.shared.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw OSSError.invalidResponse
        }
        
        print("📡 [OSS] 响应状态码: \(httpResponse.statusCode)")
        
        guard (200...299).contains(httpResponse.statusCode) else {
            // 打印错误响应内容
            if let errorString = String(data: data, encoding: .utf8) {
                print("❌ [OSS] 错误响应: \(errorString)")
            }
            throw OSSError.uploadFailed(statusCode: httpResponse.statusCode)
        }
        
        print("✅ [OSS] 上传成功")
        
        // 返回文件的公网访问 URL
        return ossURL
    }
    
    /// 生成 OSS 签名
    private func generateSignature(
        method: String,
        contentType: String,
        date: String,
        ossHeaders: [String: String],
        resource: String
    ) -> String {
        let config = AppConfig.OSS.self
        
        // 构建待签名字符串
        var stringToSign = "\(method)\n"
        stringToSign += "\n" // Content-MD5 (可选)
        stringToSign += "\(contentType)\n"
        stringToSign += "\(date)\n"
        
        // 添加 CanonicalizedOSSHeaders (如果有)
        let sortedOSSHeaders = ossHeaders.sorted { $0.key < $1.key }
        for (key, value) in sortedOSSHeaders {
            stringToSign += "\(key.lowercased()):\(value)\n"
        }
        
        // 添加 CanonicalizedResource
        stringToSign += resource
        
        // 使用 HMAC-SHA1 签名
        let signature = hmacSHA1(key: config.accessKeySecret, data: stringToSign)
        return signature
    }
    
    /// HMAC-SHA1 签名并 Base64 编码
    private func hmacSHA1(key: String, data: String) -> String {
        let keyData = key.data(using: .utf8)!
        let dataData = data.data(using: .utf8)!
        
        var macOut = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        keyData.withUnsafeBytes { keyBytes in
            dataData.withUnsafeBytes { dataBytes in
                CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
                       keyBytes.baseAddress, keyData.count,
                       dataBytes.baseAddress, dataData.count,
                       &macOut)
            }
        }
        
        let macData = Data(macOut)
        return macData.base64EncodedString()
    }
}

// MARK: - RFC 1123 日期格式化
struct RFC1123DateFormatter {
    private static let formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(abbreviation: "GMT")
        formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
        return formatter
    }()
    
    static func string(from date: Date) -> String {
        return formatter.string(from: date)
    }
}

// MARK: - 错误类型
enum OSSError: LocalizedError {
    case invalidURL
    case invalidResponse
    case uploadFailed(statusCode: Int)
    
    var errorDescription: String? {
        switch self {
        case .invalidURL:
            return "无效的 OSS URL"
        case .invalidResponse:
            return "无效的服务器响应"
        case .uploadFailed(let statusCode):
            return "上传失败，状态码: \(statusCode)"
        }
    }
}
